package com.brutal.minigames.gop;

import java.util.LinkedList;
import java.util.logging.Logger;

import com.brutal.utils.PathFinder;
import com.rsbuddy.script.methods.Calculations;
import com.rsbuddy.script.methods.Camera;
import com.rsbuddy.script.methods.Npcs;
import com.rsbuddy.script.methods.Objects;
import com.rsbuddy.script.methods.Players;
import com.rsbuddy.script.methods.Widgets;
import com.rsbuddy.script.wrappers.Component;
import com.rsbuddy.script.wrappers.GameObject;
import com.rsbuddy.script.wrappers.Item;
import com.rsbuddy.script.wrappers.Npc;
import com.rsbuddy.script.wrappers.Tile;
import com.rsbuddy.script.wrappers.TilePath;

import org.rsbuddy.tabs.Inventory;

public class Play extends Task {

	private final int airAltar = 2478;
	private final int bodyAltar = 2483;
	private final int earthAltar = 2481;
	private final int fireAltar = 2482;
	private final int mindAltar = 2479;
	private final int waterAltar = 2480;
	private final boolean defend;
	private final int greenAttractor = 13645;
	private final int greenBarrierGenerator = 13647;
	private final int greenRepeller = 13646;
	private final int yellowAttractor = 13643;
	private final int yellowBarrierGenerator = 13648;
	private final int yellowRepeller = 13644;
	private final int greenOrb = 8025;
	private final int yellowOrb = 8021;
	private String status = "Waiting";
	public Tile orbTile = null;
	public Tile altarTile = null;
	public Tile[] path = null;
	public Tile cornerTile = null;
	public Tile walkTile = null;

	public Play(final boolean defend) {
		this.defend = defend;
	}

	@Override
	public boolean isValid() {
		final GameObject altar = Objects.getNearest(airAltar, bodyAltar,
				earthAltar, fireAltar, mindAltar, waterAltar);
		final Npc orb = Npcs.getNearest(greenOrb, yellowOrb);
		return altar != null || orb != null;
	}

	@Override
	public void execute() {
		final Team team = getTeam();
		final Npc exitPortal = Npcs.getNearest(8020);
		final Npc orb = Npcs
				.getNearest(defend ? (team == Team.GREEN ? yellowOrb : greenOrb)
						: (team == Team.GREEN ? greenOrb : yellowOrb));
		final GameObject altar = Objects.getNearest(airAltar, bodyAltar,
				earthAltar, fireAltar, mindAltar, waterAltar);
		final int[] essenceId = { 1436, 7936 };
		final Component craft = Widgets.getComponent(228, 2);
		if (Camera.getPitch() > 40 || Camera.getPitch() < 20) {
			Camera.setPitch(30);
			return;
		}
		if (altar == null || !Players.getLocal().isIdle()) {
			return;
		}
		if (orb == null) {
			final Tile altarTile = altar.getLocation().randomize(3, 3);
			if (Calculations.isTileOnScreen(altarTile)
					|| Calculations.distanceTo(altarTile) < 6) {
				status = "Walking to altar";
				if (!Calculations.isTileOnScreen(altarTile)) {
					Camera.turnTo(altarTile);
					sleep(1100, 1300);
				}
				if (!interact(altarTile, "Walk here")) {
					sleep(300, 500);
					altarTile.interact("Walk here");
				}
				sleep(1100, 1300);
				return;
			} else {
				altarTile.clickOnMap();
				sleep(1100, 1300);
				return;
			}
		}
		orbTile = orb.getLocation();
		altarTile = altar.getLocation();
		if ((Inventory.isFull() || Inventory.getCount(essenceId) >= 10)
				&& Inventory.containsOneOf(essenceId)) {
			status = "Crafting runes";
			if (craft.isVisible()) {
				craft.click();
				sleep(1100, 1300);
				return;
			} else {
				if (!interact(altar, "Craft-rune")) {
					sleep(300, 500);
					altar.interact("Craft-rune");
				}
				sleep(1100, 1300);
				return;
			}
		}
		if (exitPortal != null) {
			status = "Exiting through portal";
			if (!exitPortal.isOnScreen()) {
				Camera.turnTo(exitPortal);
				sleep(1100, 1300);
				return;
			}
			if (!exitPortal.isOnScreen()) {
				exitPortal.getLocation().randomize(5, 5).clickOnMap();
				sleep(1100, 1300);
				return;
			}
			if (!interact(exitPortal, "Enter Portal")) {
				sleep(300, 500);
				exitPortal.interact("Enter Portal");
			}
			sleep(1100, 1300);
			return;
		}
		if (!defend) {
			final Item attractor = Inventory.getItem(greenAttractor,
					yellowAttractor);
			if (Inventory.containsOneOf(greenAttractor, yellowAttractor)
					&& attractor != null) {
				attractor.click(true);
				sleep(1100, 1300);
				return;
			}
			if (!orb.isOnScreen()) {
				Camera.turnTo(orb);
				sleep(1100, 1300);
				return;
			}
			final Logger log = Logger.getLogger(BrutalGOP.class.getName());
			if (orbTile == null || altarTile == null) {
				log.severe("orbTile or altarTile == null");
				return;
			}
			final PathFinder pathFinder = new PathFinder(orbTile, altarTile);
			final TilePath tilePath = pathFinder.getCurrentTilePath();
			if (tilePath == null) {
				return;
			}
			path = tilePath.toArray();
			if (path == null) {
				return;
			}
			cornerTile = getFirstCorner(path);
			if (cornerTile == null) {
				return;
			}
			walkTile = getClosestTileToCorner(cornerTile, orb.getLocation(),
					path);
			if (walkTile == null) {
				return;
			}
			if (!Players.getLocal().getLocation().equals(walkTile)) {
				if (Calculations.isTileOnScreen(walkTile)
						|| Calculations.distanceTo(walkTile) < 6) {
					status = "Walking to orb";
					if (!Calculations.isTileOnScreen(walkTile)) {
						Camera.turnTo(walkTile);
						sleep(1100, 1300);
					}
					if (!interact(walkTile, "Walk here")) {
						sleep(300, 500);
						walkTile.interact("Walk here");
					}
					sleep(1100, 1300);
				} else {
					walkTile.clickOnMap();
					sleep(1100, 1300);
				}
			}
			if (Players.getLocal().getLocation().equals(walkTile)) {
				status = "Attracting orb";
				if (!interact(orb, "Attract "
						+ (team == Team.GREEN ? "Green Orb" : "Yellow Orb"))) {
					sleep(300, 500);
					orb.interact("Attract "
							+ (team == Team.GREEN ? "Green Orb" : "Yellow Orb"));
				}
				sleep(1100, 1300);
			}
			return;
		} else if (defend) {
			final Item repeller = Inventory.getItem(greenRepeller,
					yellowRepeller);
			if (Inventory.containsOneOf(greenRepeller, yellowRepeller)
					&& repeller != null) {
				repeller.click(true);
				sleep(1100, 1300);
			}
			if (Calculations.distanceBetween(orb.getLocation(),
					altar.getLocation()) < Calculations.distanceTo(altar
					.getLocation())) {
				status = "Walking to orb";
				final Tile close = new Tile(orb.getLocation().getX()
						- Math.abs((orb.getLocation().getX() - altar
								.getLocation().getX()) / 4), orb.getLocation()
						.getY()
						- Math.abs((orb.getLocation().getY() - altar
								.getLocation().getY()) / 4));
				if (Calculations.isTileOnScreen(close)
						|| Calculations.distanceTo(close) < 6) {
					if (!Calculations.isTileOnScreen(close)) {
						Camera.turnTo(close);
						sleep(1100, 1300);
					}
					if (!interact(close, "Walk here")) {
						sleep(300, 500);
						close.interact("Walk here");
					}
					sleep(1100, 1300);
				} else {
					close.clickOnMap();
					sleep(1100, 1300);
				}
			}
			if (!orb.isOnScreen()) {
				Camera.turnTo(orb);
				sleep(1100, 1300);
			}
			status = "Repelling orb";
			if (!interact(orb, "Repell "
					+ (team == Team.GREEN ? "Yellow Orb" : "Green Orb"))) {
				sleep(300, 500);
				orb.interact("Repell "
						+ (team == Team.GREEN ? "Yellow Orb" : "Green Orb"));
			}
			sleep(1100, 1300);
			return;
		}
	}

	@Override
	public String getStatus() {
		return status;
	}

	private Tile getClosestTileToCorner(final Tile corner, final Tile orb,
			final Tile[] path) {
		if (corner == null || orb == null || path == null) {
			return null;
		}
		final LinkedList<Tile> adjacentTiles = adjacentTilesTo(corner);
		for (int i = 0; i < adjacentTiles.size(); i++) {
			final Tile tile = adjacentTiles.get(i);
			if (tile == null) {
				continue;
			}
			if (pathContains(path, tile)) {
				continue;
			}
			if (isParallelTo(tile, orb)) {
				return tile;
			}
		}
		return null;
	}

	private boolean pathContains(final Tile[] path, final Tile tile) {
		for (Tile t : path) {
			if (t.equals(tile)) {
				return true;
			}
		}
		return false;
	}

	private LinkedList<Tile> adjacentTilesTo(final Tile t) {
		final LinkedList<Tile> adjacent = new LinkedList<Tile>();
		if (validTile(new Tile(t.getX() - 1, t.getY()))) {
			adjacent.add(new Tile(t.getX() - 1, t.getY()));
		}
		if (validTile(new Tile(t.getX() + 1, t.getY()))) {
			adjacent.add(new Tile(t.getX() + 1, t.getY()));
		}
		if (validTile(new Tile(t.getX(), t.getY() - 1))) {
			adjacent.add(new Tile(t.getX(), t.getY() - 1));
		}
		if (validTile(new Tile(t.getX(), t.getY() + 1))) {
			adjacent.add(new Tile(t.getX(), t.getY() + 1));
		}
		return adjacent;
	}

	private boolean validTile(final Tile t) {
		if (t == null) {
			return false;
		}
		final GameObject go = Objects.getTopAt(t);
		if (go == null || Objects.getAllAt(t).length == 0) {
			return true;
		}
		if (go.getId() < 2478 && go.getId() > 2480 && go.getId() != 32731
				&& go.getId() != 29302) {
			return true;
		}
		return false;
	}

	private Tile getFirstCorner(final Tile[] path) {
		Tile last = null;
		for (int i = 0; i < path.length; i++) {
			final Tile tile = path[i];
			if (last == null) {
				last = path[0];
				continue;
			}
			if (isParallelTo(tile, last)) {
				last = path[i - 1];
				continue;
			} else {
				return path[i - 1];
			}
		}
		return null;
	}

	private boolean isParallelTo(final Tile parallel, final Tile to) {
		return parallel.getX() == to.getX() || parallel.getY() == to.getY();
	}

	private boolean isInGame() {
		return isValid();
	}

	public Team getTeam() {
		if (!isInGame()) {
			return null;
		}
		if (Inventory.containsOneOf(greenAttractor, greenBarrierGenerator,
				greenRepeller)) {
			return Team.GREEN;
		} else if (Inventory.containsOneOf(yellowAttractor,
				yellowBarrierGenerator, yellowRepeller)) {
			return Team.YELLOW;
		} else {
			return null;
		}
	}
}